<?php


namespace Anchu\Cockpit\Decorators\Actions;

use App\Decorators\Decorator;
use Lvzmen\Helper\iArrayHelper;

// 定制化脱敏
class UnSensibleV2 extends Action
{
    /**
     * 按照产品最新脱敏文档定制的脱敏方案
     *
     * example:
     * data = [
     *     'name' => '陈致威',
     *     'mobile' => '18153220972',
     *     'email' => 'chenzhiwei@qq.com',
     *     'idCheck' => '332527199807262538',
     *     'idUncheck' => '332527199807262538',
     *     'tel' => '0571-3261866',
     *     'phone' => '6261861',
     *     'back' => '6223475832600185',
     *     'card' => '6223475832600185112'
     * ];
     *
     *  $decorator = new Decorator($data);
     *  $result = $decorator->unSensibleV2([
     *      'name' => ['name'],
     *      'mobile' => ['mobile', 'tel', 'phone'],
     *      'idCheck' => ['idCheck'],
     *      'idUncheck' => ['idUncheck'],
     *      'bank' => ['back'],
     *      'other' => ['card'],
     *  ])->all();
     *
     * result:
     * [
     *      "name" => "*致威"
     *      "mobile" => "181****0972"
     *      "email" => "che***@qq.com"
     *      "idCheck" => "3***7199807*****8"
     *      "idUncheck" => "3****************8"
     *      "tel" => "0571****1866"
     *      "phone" => "***1861"
     *      "back" => "622347******0185"
     *      "card" => "622347******185112"
     *  ]
     *
     * 对于字段名称和类型名称一致的时候，有简便写法：
     * // 万能写法
     * $decorator->unSensibleV2(['name' => ['username']])
     * // 只有一个元素的时候
     * $decorator->unSensibleV2(['name' => 'username'])
     * // 当字段名称和类型一致的时候：
     * $decorator->unSensibleV2(['name' => 'name'])
     * 同等于：
     * $decorator->unSensibleV2(['name'])
     *
     * 目前支持的脱敏类型：
     * - name：姓名（*致威）
     * - idCheck: 身份证号：需要用户确认的脱敏方式（3***7199807*****8）
     * - idUnCheck: 身份证号：不需要用户确认的脱敏方式（3****************8）
     * - idUnCheck: 身份证号：不需要用户确认的脱敏方式（3****************8）
     * - mobile：电话号码，支持如下三种模式
     *      - 手机号（181****0972）
     *      - 座机号（0571****1866）
     *      - 短号（***1861）
     * - email: 邮箱，支持如下两种情况
     *      - @前字符串小于3位：ch@qq.com => ch***@qq.com
     *      - @前字符串大于3位：che***@qq.com => ch***@qq.com
     *
     * @var Decorator
     */
    public $decorator;

    public function run($arguments): Decorator
    {
        $map = $arguments[0] ?? [];

        if (is_array($map)) {
            // 关联数组
            $this->decorator->data = self::unSensible($this->decorator->data, $map);
        }

        return $this->decorator;
    }

    /**
     * 递归脱敏，直到非数组类型的值
     * @param array $data
     * @param array $map
     * @return array
     */
    public static function unSensible($data = [], $map = []): array
    {
        try {
            foreach ($data as $key => $item) {
                if (is_array($item)) {
                    $data[$key] = self::unSensible($item, $map);
                } else {
                    foreach ($map as $type => $columns) {
                        $available = false;
                        // $map = ['name' => ['host']]
                        if (iArrayHelper::isIndexed($columns) && in_array($key, $columns)) {
                            $available = true;
                        }
                        // $map = ['name' => 'host']
                        if (is_string($columns) && $key == $columns) {
                            $available = true;
                        }
                        // $map = ['name']
                        if (is_integer($type) && $key == $columns) {
                            $available = true;
                            $type = $key;
                        }

                        if ($available) {
                            $data[$key] = self::methods($type, $item);
                        }
                    }
                }
            }
            return $data;
        } catch (\Exception $e) {
            var_dump($e->getMessage(), $e->getLine());
            die;
        }
    }

    /**
     * 实际脱敏方案代码，可追加
     * @param String $type // 脱敏类型，如：name, mobile
     * @param String $item // 脱敏目标值
     * @return string
     */
    private static function methods(string $type, string $item)
    {
        $result = '';
        if (empty($item) && is_null($item)) {
            return $item;
        }
        switch ($type) {
            case 'name':
                // 姓名
                $result = '*' . mb_substr($item, 1);
                break;
            case 'idCheck':
                // 需要用户确认的脱敏方式
                if (strlen($item) == 18) {
                    $result = mb_substr($item, 0, 1)
                        . '***'
                        . mb_substr($item, 4, 8)
                        . '*****'
                        . mb_substr($item, -1, 1);
                    break;
                }
            case 'idUnCheck':
                // 不需要用户确认的脱敏方式
                $result = mb_substr($item, 0, 1)
                    . str_repeat('*', strlen($item) - 2)
                    . mb_substr($item, -1, 1);
                break;
            case 'mobile':
                if (strlen($item) > 7 && mb_substr($item, 0, 1) == '0') {
                    // 固定电话
                    $result = mb_substr($item, 0, 4)
                        . '****'
                        . mb_substr($item, -4);
                } else if (strlen($item) > 10) {
                    // 手机号码
                    $result = mb_substr($item, 0, 3)
                        . '****'
                        . mb_substr($item, -4);
                } else {
                    // 处理短号：6261861
                    $result = '***' . mb_substr($item, -4);
                }
                break;
            case 'email':
                // 先处理邮箱：chenzhiwei@hzanchu.com => che***@hzanchu.com
                $arr = explode('@', $item);
                if (!isset($arr[1])) {
                    break;
                }
                if (strlen($arr[0]) < 3) {
                    $result = $arr[0] . '***' . '@' . $arr[1];
                } else {
                    $result = mb_substr($arr[0], 0, 3) . '***' . '@' . $arr[1];
                }
                break;
            case 'bank':
                // 银行卡号
                $result = mb_substr($item, 0, 6)
                    . str_repeat('*', strlen($item) - 10)
                    . mb_substr($item, -4);
                break;
            case 'other':
                // 其他证件号，如：军官证、护照
                $length = floor(strlen($item) / 3);
                $result = mb_substr($item, 0, $length)
                    . str_repeat('*', $length)
                    . mb_substr($item, 0 - $length);
                break;
            default:
                break;
        }

        return $result;
    }
}
